using System;
using System.Globalization;
using ConvertSourceToHtml.Interop;

namespace ConvertSourceToHtml.Conversion.HtmlCodeElements
{

    /// <summary>
    /// Represents a color in HTML.
    /// </summary>
    public class HtmlColor
    {
		#region Static Methods

		/// <summary>
		/// Adjusts an <see cref="HtmlColor"/> by the specified percentage.
		/// </summary>
		/// <param name="original">DOCUMENTME</param>
		/// <param name="adjustment">DOCUMENTME</param>
		/// <returns>The resulting <see cref="HtmlColor"/>.</returns>
		internal static HtmlColor AdjustColor(HtmlColor original, double adjustment)
		{
			return new HtmlColor(AdjustLevel(original.RedLevel, adjustment), AdjustLevel(original.GreenLevel, adjustment), AdjustLevel(original.BlueLevel, adjustment));
		}

		/// <summary>
		/// DOCUMENTME
		/// </summary>
		/// <param name="original">DOCUMENTME</param>
		/// <param name="adjustment">DOCUMENTME</param>
		/// <returns>DOCUMENTME</returns>
		private static byte AdjustLevel(byte original, double adjustment)
		{
			double adjusted;

			adjusted = (double)original + (255.0d * adjustment);
			if (adjusted < 0)
			{
				adjusted = 0;
			}
			else if (adjusted > 255)
			{
				adjusted = 255;
			}
			return (byte)adjusted;
		}

		/// <summary>
		/// Converts an OLE color value to an <see cref="HtmlColor"/>.
		/// </summary>
		/// <param name="oleColor">The OLE color value.</param>
		/// <returns>The resulting <see cref="HtmlColor"/>.</returns>
		/// <exception cref="ArgumentException">Thrown if <paramref name="oleColor"/> is not a 
		/// valid OLE color value.</exception>
		internal static HtmlColor ConvertOleColor(uint oleColor)
		{
			uint refColor;
			uint result;
			byte redLevel;
			byte greenLevel;
			byte blueLevel;

			refColor = 0;
			result = NativeMethods.OleTranslateColor(oleColor, 0, ref refColor);
			if (result != 0)
			{
				throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "OleTranslateColor returned {0} for OLE color {1}.", result, oleColor));
			}

			redLevel = (byte)(refColor & 0xFF);
			greenLevel = (byte)((refColor >> 8) & 0xFF);
			blueLevel = (byte)((refColor >> 16) & 0xFF);

			return new HtmlColor(redLevel, greenLevel, blueLevel);
		}

		#endregion // Static Methods

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="HtmlColor"/> class with the specified red,
        /// green, and blue levels.
        /// </summary>
        /// <param name="redLevel">The red level.</param>
        /// <param name="greenLevel">The green level.</param>
        /// <param name="blueLevel">The blue level.</param>
        public HtmlColor(byte redLevel, byte greenLevel, byte blueLevel)
        {
			RedLevel = redLevel;
			GreenLevel = greenLevel;
			BlueLevel = blueLevel;
        }

		/// <summary>
        /// Private constructor required for XML serialization.
        /// </summary>
		private HtmlColor()
		{
		}

		#endregion // Constructors

		#region Properties

		/// <summary>
		/// Gets or sets the red level.
		/// </summary>
		public byte RedLevel { get; set; }

		/// <summary>
		/// Gets or sets the green level.
		/// </summary>
		public byte GreenLevel { get; set; }

		/// <summary>
		/// Gets or sets the blue level.
		/// </summary>
		public byte BlueLevel { get; set; }

		#endregion // Fields


        #region Methods

        /// <summary>
        /// Returns the string representation of the color.
        /// </summary>
        /// <returns>A string representation of the color.</returns>
        public override string ToString()
        {
			string color;

			color = String.Format(CultureInfo.InvariantCulture, "#{0:x2}{1:x2}{2:x2}", RedLevel, GreenLevel, BlueLevel);
			switch (color)
			{
				case "#00ffff":
					color = "aqua";
					break;
				case "#000000":
					color = "black";
					break;
				case "#0000ff":
					color = "blue";
					break;
				case "#ff00ff":
					color = "fuchsia";
					break;
				case "#808080":
					color = "gray";
					break;
				case "#008000":
					color = "green";
					break;
				case "#00ff00":
					color = "lime";
					break;
				case "#800000":
					color = "maroon";
					break;
				case "#000080":
					color = "navy";
					break;
				case "#808000":
					color = "olive";
					break;
				case "#800080":
					color = "purple";
					break;
				case "#ff0000":
					color = "red";
					break;
				case "#c0c0c0":
					color = "silver";
					break;
				case "#008080":
					color = "teal";
					break;
				case "#ffffff":
					color = "white";
					break;
				case "#ffff00":
					color = "yellow";
					break;
			}
			return color;
		}

		/// <summary>
		/// Returns whether the specified object is equal to the color.
		/// </summary>
		/// <param name="obj"></param>
		/// <returns></returns>
		public override bool Equals(object obj)
		{
			HtmlColor color;

			color = obj as HtmlColor;
			return ((color != null) && ToString().Equals(color.ToString()));
		}

		#endregion // Methods
    }

}
